/******************************************************************************
 *
 * Component: OGDI Core C API
 * Purpose: Implementation of BSD directory routines for MS-DOS.
 * 
 ******************************************************************************
 * @(#)dir.c 1.4 87/11/06 Public Domain. 
 * 
 *  A public domain implementation of BSD directory routines for 
 *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield), 
 *  August 1897 
 *  Ported to OS/2 by Kai Uwe Rommel 
 *  December 1989, February 1990 
 *  Ported to Windows NT 22 May 91 
 *    other mods Summer '92 brianmo@microsoft.com 
 *  opendirx() was horribly written, very inefficient, and did not take care
 *    of all cases.  It is still not too clean, but it is far more efficient.
 *    Changes made by Gordon Chaffee (chaffee@bugs-bunny.cs.berkeley.edu)
 ******************************************************************************
 *
 * $Log$
 * Revision 1.2  2001-04-09 15:04:34  warmerda
 * applied new source headers
 *
 */

/* 
   dir.c for MS-DOS by Samuel Lam <skl@van-bc.UUCP>, June/87 
*/ 
 
/* #ifdef WIN32 */
 
 
#ifdef _WINDOWS

/*Includes: 
 *	crt 
 */ 
#include <windows.h>
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include "opendir.h" 

#define stat _stat

/* 
 *	NT specific 
 */ 
#include <stdio.h> 
 
/* 
 *	random typedefs 
 */ 
#define HDIR        HANDLE 
#define HFILE       HANDLE 
#define PHFILE      PHANDLE 
 
/* 
 *	local functions 
 */ 
static char *getdirent(char *); 
static void free_dircontents(struct _dircontents *); 
 
static HDIR				FindHandle; 
static WIN32_FIND_DATA	FileFindData; 
 
static struct dirent dp; 
 
DIR *opendirx(char *name, char *pattern) 
{ 
    struct stat statb; 
    DIR *dirp; 
    char c; 
    char *s; 
    struct _dircontents *dp; 
    int len;
    int unc;
    char path[ OFS_MAXPATHNAME ]; 
    register char *ip, *op;

    for (ip = name, op = path; ; op++, ip++) {
	*op = *ip;
	if (*ip == '\0') {
	    break;
	}
    }
    len = ip - name;
    if (len > 0) {
	unc = ((path[0] == '\\' || path[0] == '/') &&
	       (path[1] == '\\' || path[1] == '/'));
	c = path[len - 1];
	if (unc) {
	    if (c != '\\' && c != '/') {
		path[len] = '/';
		len++;
		path[len] ='\0';
	    }
	} else {
	    if ((c == '\\' || c == '/') && (len > 1)) {
		len--;
		path[len] = '\0';
 
		if (path[len - 1] == ':' ) {
		    path[len] = '/'; len++;
		    path[len] = '.'; len++;
		    path[len] = '\0';
		}
	    } else if (c == ':' ) {
		path[len] = '.';
		len++;
		path[len] ='\0';
	    }
	}
    } else {
	unc = 0;
	path[0] = '.';
	path[1] = '\0';
	len = 1;
    }
 
    if (stat(path, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) {
	return NULL; 
    }

    dirp = malloc(sizeof(DIR));
    if (dirp == NULL) {
	return dirp;
    }
 
    c = path[len - 1];
    if (c == '.' ) {
	if (len == 1) {
	    len--;
	} else {
	    c = path[len - 2];
	    if (c == '\\' || c == ':') {
		len--;
	    } else {
		path[len] = '/';
		len++;
	    }
	}
    } else if (!unc && ((len != 1) || (c != '\\' && c != '/'))) {
	path[len] = '/';
	len++;
    }
    strcpy(path + len, pattern);
 
    dirp -> dd_loc = 0; 
    dirp -> dd_contents = dirp -> dd_cp = NULL; 
 
    if ((s = getdirent(path)) == NULL) {
	return dirp;
    }
 
    do 
    { 
	if (((dp = malloc(sizeof(struct _dircontents))) == NULL) || 
	    ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      ) 
	{ 
	    if (dp) 
		free(dp); 
	    free_dircontents(dirp -> dd_contents); 
 
	    return NULL; 
	} 
 
	if (dirp -> dd_contents) 
	    dirp -> dd_cp = dirp -> dd_cp -> _d_next = dp; 
	else 
	    dirp -> dd_contents = dirp -> dd_cp = dp; 
 
	strcpy(dp -> _d_entry, s); 
	dp -> _d_next = NULL; 
 
    } 
    while ((s = getdirent(NULL)) != NULL); 
 
    dirp -> dd_cp = dirp -> dd_contents; 
    return dirp; 
} 
 
DIR *opendir(char *name)
{
  return opendirx(name, "*");
} 

void closedir(DIR * dirp) 
{ 
  free_dircontents(dirp -> dd_contents); 
  free(dirp); 
} 
 
struct dirent *readdir(DIR * dirp) 
{ 
  /* static struct dirent dp; */ 
  if (dirp -> dd_cp == NULL) 
    return NULL; 
 
  /*strcpy(dp.d_name,dirp->dd_cp->_d_entry); */ 
 
  dp.d_name = dirp->dd_cp->_d_entry; 
 
  dp.d_namlen = dp.d_reclen = 
    strlen(dp.d_name); 
 
  dp.d_ino = dirp->dd_loc+1; /* fake the inode */ 
 
  dirp -> dd_cp = dirp -> dd_cp -> _d_next; 
  dirp -> dd_loc++; 
 
 
  return &dp; 
} 
 
void seekdir(DIR * dirp, long off) 
{ 
  long i = off; 
  struct _dircontents *dp; 
 
  if (off >= 0) 
  { 
    for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next); 
 
    dirp -> dd_loc = off - (i + 1); 
    dirp -> dd_cp = dp; 
  } 
} 
 
 
long telldir(DIR * dirp) 
{ 
  return dirp -> dd_loc; 
} 
 
static void free_dircontents(struct _dircontents * dp) 
{ 
  struct _dircontents *odp; 
 
  while (dp) 
  { 
    if (dp -> _d_entry) 
      free(dp -> _d_entry); 
 
    dp = (odp = dp) -> _d_next; 
    free(odp); 
  } 
} 
/* end of "free_dircontents" */ 
 
static char *getdirent(char *dir) 
{ 
    int got_dirent; 

    if (dir != NULL) 
    {				       /* get first entry */ 
	if ((FindHandle = FindFirstFile( dir, &FileFindData )) 
	    == (HDIR)0xffffffff) 
	{ 
	    return NULL; 
	} 
	got_dirent = 1;
    } 
    else				       /* get next entry */ 
	got_dirent = FindNextFile( FindHandle, &FileFindData ); 
 
    if (got_dirent) 
	return FileFindData.cFileName; 
    else 
    { 
	FindClose(FindHandle); 
	return NULL; 
    } 
} 
/* end of getdirent() */ 

struct passwd * _cdecl
getpwnam(char *name)
{
    return NULL;
}

struct passwd * _cdecl
getpwuid(int uid)
{
    return NULL;
}

int
getuid()
{
    return 0;
}

void _cdecl
endpwent(void)
{
}

#endif /* WINDOWS */
